import { Box, Button, Grid, Typography } from '@mui/material';
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';

import Disbursement from '../../../api/disbursement/disbursement';
import FeeManager from '../../../api/fee/fee-manager';
import PayrollGroup from '../../../api/payroll-group/payroll-group';
import PayrollGroupManager from '../../../api/payroll-group/payroll-group-manager';
import PayrollGroupMemberManager, {
    GetPayrollGroupMembersWithPayoutResponse
} from '../../../api/payroll-group-member/payroll-group-member-manager';
import TokenManager, { Network } from '../../../api/token/token-manager';
import Transaction from '../../../api/transaction/transaction';
import HomeReviewCSV from '../../../components/csv-disbursements/home-review-csv';
import HomeReviewCSVWithError, {
    TransactionsWithError
} from '../../../components/csv-disbursements/home-review-csv-with-error';
import SaveDisbursementPopup from '../../../components/csv-disbursements/save-disbursement-popup';
import MainLayout from '../../../components/HOCs/main-layout';
import {
    confirmDisbursementDialog,
    payDisbursementDialog,
    successDisbursementDialog
} from '../../../components/shared/dialogs/disbursement-flow';
import { createDialog } from '../../../components/shared/dialogs/dynamic-dialogs';
import { DialogTypes } from '../../../components/shared/dialogs/dynamic-dialogs/types-mapping';
import { DisbursementFlow, DisbursementType } from '../../../constants/disbursement-flow';

export default function CSVDisbursementPage() {
    const router = useRouter();
    const [payrollGroup, setPayrollGroup] = useState<PayrollGroup>();

    const [token, setToken] = useState('');
    const [abi, setAbi] = useState(null);
    const [network, setNetwork] = useState<Network>(null);
    const [transactions, setTransactions] = useState<Array<Transaction>>([]);
    const [transactionsWithErrors, setTransactionsWithErrors] =
        useState<Array<TransactionsWithError>>();

    const [flow, setFlow] = useState(DisbursementFlow.START);
    const [disbursement, setDisbursement] = useState<Disbursement>(null);

    const [minAmount, setMinAmount] = useState<number>(0);
    const [transactionFee, setTransactionFee] = useState<number>(0);
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        const getSlpFee = async () => {
            const slpFee = await FeeManager.getSLP();
            if (slpFee) {
                const minAmount = !Number.isNaN(Number(slpFee.minimumAmount))
                    ? Number(slpFee.minimumAmount)
                    : 0;
                const transactionFee = !Number.isNaN(Number(slpFee.gasFee.amount))
                    ? Number(slpFee.gasFee.amount)
                    : 0;
                setMinAmount(minAmount);
                setTransactionFee(transactionFee);
            }
        };
        getSlpFee().then();
    }, []);

    useEffect(() => {
        if (!router.isReady) return;
        const id = parseInt(router.query.id.toString());

        PayrollGroupManager.getByID(id).then((payrollGroup: PayrollGroup) => {
            setPayrollGroup(payrollGroup);
            setToken(payrollGroup.currency);
        });
    }, [router.isReady]);

    useEffect(() => {
        if (payrollGroup) {
            setLoading(true);
            PayrollGroupMemberManager.getAllWithPayouts(payrollGroup.id)
                .then((response: Array<GetPayrollGroupMembersWithPayoutResponse>) => {
                    const transactions: Transaction[] = [];
                    const transactionsWithErrors: TransactionsWithError[] = [];

                    for (let i = 0; i < response.length; i++) {
                        const transaction = new Transaction();
                        transaction.csvLine = response[i].member.id;
                        transaction.name = response[i].member.name;
                        transaction.amount = response[i].slp;
                        transaction.walletAddress = response[i].member.memberRoninWalletAddress;
                        transaction.email = response[i].member.email;
                        transaction.memberID = response[i].member.id;

                        if (minAmount > transaction.amount) {
                            transactionsWithErrors.push({
                                transaction: transaction,
                                error: 'Minimum GFS amount: ' + minAmount + payrollGroup.currency
                            });
                        } else if (payrollGroup.minimumPayoutAmount > transaction.amount) {
                            transactionsWithErrors.push({
                                transaction: transaction,
                                error:
                                    'Minimum Payroll Group amount: ' +
                                    payrollGroup.minimumPayoutAmount +
                                    payrollGroup.currency
                            });
                        } else {
                            transactions.push(transaction);
                        }
                    }

                    setTransactionsWithErrors(transactionsWithErrors);
                    setTransactions(transactions);
                    setFlow(DisbursementFlow.REVIEW_CSV);
                })
                .finally(() => setLoading(false));
        }
    }, [payrollGroup, minAmount]);

    useEffect(() => {
        const getTokens = async () => {
            const { abi, tokens } = await TokenManager.getTokens();
            setAbi(abi);

            for (let x = 0; x < tokens.length; x++) {
                if (tokens[x].token == 'SLP') {
                    for (let y = 0; y < tokens[x].networks.length; y++) {
                        if (tokens[x].networks[y].id == 'ronin') {
                            console.log(tokens[x].networks[y]);
                            setNetwork(tokens[x].networks[y]);
                        }
                    }
                }
            }
        };
        getTokens().then();
    }, []);

    useEffect(() => {
        switch (flow) {
            case DisbursementFlow.CONFIRM:
                createDialog(DialogTypes.DISBURSEMENT_FLOW_CONFIRM, () =>
                    confirmDisbursementDialog({
                        open: true,
                        data: {
                            transactions,
                            token,
                            transactionFee,
                            network,
                            abi,
                            disbursement
                        },
                        onSubmit: (flow) => {
                            flow && setFlow(flow);
                        }
                    })
                );
                break;
            case DisbursementFlow.PAY:
                createDialog(DialogTypes.DISBURSEMENT_FLOW_PAY, () =>
                    payDisbursementDialog({
                        open: true,
                        data: { transactions, token, disbursement, transactionFee, abi, network },
                        onSubmit: () => setFlow(DisbursementFlow.SUCCESS)
                    })
                );
                break;
            case DisbursementFlow.SUCCESS:
                createDialog(DialogTypes.DISBURSEMENT_FLOW_SUCCESS, () =>
                    successDisbursementDialog({
                        open: true,
                        disbursement
                    })
                );
                break;
        }
    }, [flow]);

    const updateFlow = async (flow: DisbursementFlow, disbursement: Disbursement = null) => {
        if (disbursement != null) {
            setDisbursement(disbursement);
        }
        setFlow(flow);
    };

    const hasTransactions = (): boolean => {
        return transactions && transactions.length > 0;
    };

    const hasTransactionsWithErrors = (): boolean => {
        return transactionsWithErrors && transactionsWithErrors.length > 0;
    };

    const onDisburseClick = async (event) => {
        event.preventDefault();

        setFlow(DisbursementFlow.SAVE_TRANSACTIONS);
    };

    return (
        <>
            <MainLayout>
                <Box sx={{ p: 6 }}>
                    <Typography variant="h1" className="bottom-30">
                        Axie Infinity Disbursement
                    </Typography>

                    {payrollGroup && <Typography variant="h2">{payrollGroup.name}</Typography>}

                    {loading && (
                        <Typography variant="h6" color="white" pt={2}>
                            Loading...
                        </Typography>
                    )}

                    {(flow == DisbursementFlow.REVIEW_CSV ||
                        flow == DisbursementFlow.SAVE_TRANSACTIONS ||
                        flow == DisbursementFlow.CONFIRM ||
                        flow == DisbursementFlow.PAY ||
                        flow == DisbursementFlow.SUCCESS) &&
                        hasTransactions() && (
                            <div className="top-10">
                                <HomeReviewCSV transactions={transactions} token={token} />

                                <Grid
                                    className="top-30 bottom-30"
                                    container
                                    justifyContent="center"
                                >
                                    <Button
                                        variant="contained"
                                        component="label"
                                        onClick={onDisburseClick}
                                    >
                                        SEND DISBURSEMENT
                                    </Button>
                                </Grid>
                            </div>
                        )}

                    {(flow == DisbursementFlow.REVIEW_CSV ||
                        flow == DisbursementFlow.SAVE_TRANSACTIONS ||
                        flow == DisbursementFlow.CONFIRM ||
                        flow == DisbursementFlow.PAY ||
                        flow == DisbursementFlow.SUCCESS) &&
                        hasTransactionsWithErrors() && (
                            <div className="top-30">
                                <Typography variant="h2">
                                    Members That Didn't Meet the Criteria
                                </Typography>
                                <HomeReviewCSVWithError
                                    transactions={transactionsWithErrors}
                                    token={token}
                                />
                            </div>
                        )}

                    {flow == DisbursementFlow.SAVE_TRANSACTIONS && (
                        <SaveDisbursementPopup
                            title={payrollGroup.name}
                            token={token}
                            network={network}
                            updateFlow={updateFlow}
                            transactions={transactions}
                            type={DisbursementType.AXIE_INFINITY}
                        />
                    )}
                </Box>
            </MainLayout>
        </>
    );
}
